#! /bin/sh

# Copyright (c) 2014 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
#
# This script provides various data about the internal disk to show on the
# chrome://system page. It will run once on startup to dump output to the file
# /var/log/storage_info.txt which will be read later by debugd when the user
# opens the chrome://system page.
. /usr/share/misc/chromeos-common.sh

: ${STORAGE_INFO_FILE:="/var/log/storage_info.txt"}

SSD_CMD_0="hdparm -I"
SSD_CMD_1_NORMAL="smartctl -x"
SSD_CMD_1_ALTERNATE="smartctl -a -f brief"
SSD_CMD_MAX=1

# This match SanDisk SSD U100/i100 with any size with version *.xx.* when x < 54
# Seen Error: U100 10.52.01 / i100 CS.51.00 / U100 10.01.04
MODEL_BLACKLIST_0="SanDisk_SSD_[iU]100.*"
VERSION_BLACKLIST_0="(CS|10)\.([01234].|5[0123])\..*"
MODEL_BLACKLIST_1="SanDisk_SDSA5GK-.*"
VERSION_BLACKLIST_1="CS.54.06"
BLACKLIST_MAX=1

MMC_NAME_0="cid"
MMC_NAME_1="csd"
MMC_NAME_2="date"
MMC_NAME_3="enhanced_area_offset"
MMC_NAME_4="enhanced_area_size"
MMC_NAME_5="erase_size"
MMC_NAME_6="fwrev"
MMC_NAME_7="hwrev"
MMC_NAME_8="manfid"
MMC_NAME_9="name"
MMC_NAME_10="oemid"
MMC_NAME_11="preferred_erase_size"
MMC_NAME_12="prv"
MMC_NAME_13="raw_rpmb_size_mult"
MMC_NAME_14="rel_sectors"
MMC_NAME_15="serial"
MMC_NAME_MAX=15


# Example of hdparm result
# Model=SanDisk SSD i100 32GB, FwRev=11.56.00, SerialNo=123456789012
# This command extracts the model string and replaces space with an underscore.
get_ssd_model() {
  echo "$1" | sed -e "s/^.*Model=//g" -e "s/,.*//g" -e "s/ /_/g"
}

get_ssd_version() {
  echo "$1" | sed -e "s/^.*FwRev=//g" -e "s/,.*//g" -e "s/ /_/g"
}

is_blacklist() {
  echo "$1" | grep -Eq $2
}

is_ssd_blacklist() {
  local model=$1
  local version=$2
  local model_blacklist
  local version_blacklist
  local i

  for i in $(seq 0 ${BLACKLIST_MAX}); do
    eval model_blacklist=\${MODEL_BLACKLIST_${i}}
    if is_blacklist ${model} ${model_blacklist}; then
      eval version_blacklist=\${VERSION_BLACKLIST_${i}}
      if is_blacklist ${version} ${version_blacklist}; then
        return 0
      fi
    fi
  done
  return 1
}

print_ssd_info() {
  # BUG: On some machines, smartctl -x causes SSD error (crbug.com/328587)
  # We need to check model and firmware version of the SSD to avoid this bug.

  # SSD model and firmware version is on the same line in hdparm result
  local hdparm_result="$(hdparm -i /dev/$1 | grep "Model=")"
  local model="$(get_ssd_model "${hdparm_result}")"
  local version="$(get_ssd_version "${hdparm_result}")"
  local ssd_cmd
  local i

  if is_ssd_blacklist "${model}" "${version}"; then
    SSD_CMD_1=${SSD_CMD_1_ALTERNATE}
  else
    SSD_CMD_1=${SSD_CMD_1_NORMAL}
  fi

  for i in $(seq 0 ${SSD_CMD_MAX}); do
    # use eval for variable indirection
    eval ssd_cmd=\${SSD_CMD_${i}}
    echo "$ ${ssd_cmd} /dev/$1"
    ${ssd_cmd} "/dev/$1"
    echo ""
  done
}

print_mmc_info() {
  local mmc_name
  local mmc_path
  local mmc_result
  local i

  for i in $(seq 0 ${MMC_NAME_MAX}); do
    eval mmc_name=\${MMC_NAME_${i}}
    mmc_path="/sys/block/$1/device/${mmc_name}"
    mmc_result="$(cat "${mmc_path}" 2>/dev/null)"
    printf "%-20s | %s\n" "${mmc_name}" "${mmc_result}"
  done

  mmc extcsd read "/dev/$1"
}

main() {
  local dev

  rm -f ${STORAGE_INFO_FILE}
  touch ${STORAGE_INFO_FILE}
  chmod 644 ${STORAGE_INFO_FILE}
  exec > ${STORAGE_INFO_FILE}

  # We need to check both sda and sdb for internal disk because:
  # 1) If we use rootdev command to determine the disk to check, it will return
  #    the usb stick, not the internal drive, when we boot from usb.
  # 2) We also can not assume that sda is an internal disk because in some
  #    systems (e.g., parrot), the usb stick might be labeled as sda and the
  #    internal disk as sdb.
  for dev in $(list_fixed_ata_disks); do
    print_ssd_info ${dev}
  done

  # For devices with eMMC, the internal disk will always be labeled as mmcblk0
  # so we can check only mmcblk0, but to be safe we will check both mmcblk0 and
  # mmcblk1.
  for dev in $(list_fixed_mmc_disks); do
    print_mmc_info ${dev}
  done
}

# don't run script in test mode
if [ ! "$1" = "--test" ]; then
  main
fi

